import { _decorator, Node, director, color, System, Component, NodePool, find, ScrollView, EventTarget, instantiate } from 'cc';
import { BaseView } from '../../rxjs/cc3/BaseView';
import { UITransform } from 'cc';
import dynamicScrollViewItem from './dynamicScrollViewItem';
const { ccclass, property } = _decorator;

/**
 * 实现一个新的XxxScrollView类型继承dynamicScrollViewDataV2
 * 覆盖实现两个方法:
 * 一个是getPrefab,返回一个item的prefab即可,内部会自动使用nodepool
 * 一个是fetchDataForKey:
 * 这是一个实例,里面会用异步的方式获取数据,
 * rank是必须的字段直接说明该item的位置,从0开始的整数
 * _isLast标记最后一个,也就不能继续下滑拉取了
 * 参数key,对应this.scrollView.open('#key#', 0);填啥都行,设计用于显示多组数据,可以从不同的数据源拉取,单一数据源则不用考虑
 * skip,跳过前几个,也就是从第几个idx开始获取
 * count,获取几个
 * 也就是此处需要拉去从底skip索引开始的count个数据,
 * 如下面的demo片段所示,
 * 组装好list后调用addDataFunc进行传入,对应查看dynamicScrollViewItem里面的注释
 * 
 * 
 *     fetchDataForKey(key: string, skip: number, count: number, addDataFunc: Function): void {
        this.log('fetchDataForKey', key, skip, count);
        this.scheduleOnce(function () {
            let list = [];
            for (let i = skip; i < skip + count; i++) {
                if (i >= 0 && i < 100) {
                    let stageNum = i * 100;
                    list.push({ rank: i, stageNum: stageNum, _isLast: i == 99 });
                }
            }
            addDataFunc(list);
        }, .01);
    }
 * 
 */

@ccclass
export default class dynamicScrollViewV2 extends BaseView {

    eventTarget = new EventTarget();

    @property
    compatibleMaxCount: number = 5000;

    eventPrefix: string = 'defaultDSVevent';

    @property
    preparePrefabInPoolCount: number = 10;

    content: Node = null;

    itemPool: NodePool = null;
    poolReady: boolean = false;

    itemMap: any = null;

    itemHeight: number = 0;

    halfViewHeight: number = 0;

    scrollView: ScrollView = null;

    alreadyFirstSetCompatibleMaxCount: boolean = false;

    maxRank: number = 0;

    // 用户显示效果
    minRefreshRank: number = 0;
    maxRefreshRank: number = 0;

    ready = false;

    @property
    tailHeight: number = 0;

    // onLoadView() {
    init() {
        this.content = find('view/content', this.node);
        this.eventTarget.on(this.eventPrefix + '_refresh', this.item_fade_in_refresh, this);
        this.itemPool = new NodePool();
        this.clearContent();
        this.scrollView = this.node.getComponent(ScrollView);
        this.alreadyFirstSetCompatibleMaxCount = false;
        this.ready = true;
    }

    update() {
        if (this.poolReady) {
            this.refreshContent(this.getKeyNow());
        }
    }

    getKeyNow() {
        return 'default';
    }

    // 需要重写 - 返回需要的数据列表
    getRowDataAtRank(rank, groupKey) {
        return {};
    }

    // 需要重写 - 返回prefab
    getPrefab() {
        return null;
    }

    getItemComponent(item): dynamicScrollViewItem {
        return item.getComponent(dynamicScrollViewItem);
    }

    requireFetch(rank, groupKey) {
        this.log('requireFetch 需要重写', rank);
    }

    createItem() {
        let item = null;
        if (this.itemPool.size() > 0) {
            item = this.itemPool.get();
        } else {
            item = instantiate(this.getPrefab());
            let _lbItem = this.getItemComponent(item);
            _lbItem.eventTarget = this.eventTarget;
            _lbItem.initOnce();
        }
        this.content.addChild(item);
        let lbItem = this.getItemComponent(item);
        lbItem.init();
        return lbItem;
    }

    prepare() {
        this.halfViewHeight = find('view', this.node).getComponent(UITransform).height / 2;
        this.preparePool();
    }

    preparePool() {
        let initCount = this.preparePrefabInPoolCount;
        for (let i = 0; i < initCount; ++i) {
            let item = instantiate(this.getPrefab()); // 创建节点
            let _lbItem = this.getItemComponent(item);
            _lbItem.initOnce();
            if (this.itemHeight == 0) this.itemHeight = item.getComponent(UITransform).height;
            this.itemPool.put(item); // 通过 put 接口放入对象池
        }
        this.poolReady = true;
    }

    clearPool() {
        if (this.itemPool != null) {
            this.itemPool.clear();
            this.poolReady = false;
        }
    }

    clearContent() {
        if (this.content.children.length > 0) {
            this.log('clearContent');
            this.content.children.map(_ => _).forEach(_ => {
                this.itemPool.put(_);
            });
        }
        this.itemMap = {};
        this.alreadyFirstSetCompatibleMaxCount = false;
    }

    getFirstRankInView() {
        let y = this.content.position.y;
        return Math.max(0, Math.floor((y - this.halfViewHeight) / this.itemHeight));
    }

    getLastRankInView() {
        let y = this.content.position.y;
        return Math.min(this.compatibleMaxCount, Math.floor((y + this.halfViewHeight) / this.itemHeight) + 1);
    }

    refreshContent(groupKey: string) {

        if (!this.alreadyFirstSetCompatibleMaxCount) {
            this.alreadyFirstSetCompatibleMaxCount = true;
            this.setMaxRank(this.compatibleMaxCount);
        }

        // 先根据content的y位置确定当前可以显示的rank行
        let firstRank = this.getFirstRankInView();
        let lastRank = this.getLastRankInView();

        for (let key in this.itemMap) {
            let r = Number(key);
            if (r < firstRank || r >= lastRank) {
                // this.log('remove a item', r);
                let item = this.itemMap[key];
                let lbItem = this.getItemComponent(item);
                lbItem.disappear();
                // this.itemPool.put(item.node);
                this.recycleItem(item.node);
                delete this.itemMap[key];
            }
        }

        for (let r = firstRank; r < lastRank; r++) {
            let key = '' + r;
            if (this.itemMap[key] == null) {
                // this.log('create a item', r);
                let rowData = this.getRowDataAtRank(r, groupKey);
                if (rowData) {
                    let item = this.createItem();
                    item.node.setY(this.getYPostion(r));
                    this.setItem(item, rowData, groupKey);

                    let diff = this.getDiff(r);

                    // cc.log('refreshConten', r, this.minRefreshRank, this.maxRefreshRank, diff);
                    item.appear({ diff: diff });
                    this.itemMap[key] = item;
                }
            }
        }
    }

    getYPostion(r: number) {
        return -this.itemHeight * r - this.itemHeight / 2;
    }

    recycleItem(node: Node) {
        // /** 兼容BaseView中的绑定 */
        // let baseView = node.getComponent(BaseView);
        // if (baseView) baseView.unbind();

        this.itemPool.put(node);
    }

    refreshCurrent() {
        // 先根据content的y位置确定当前可以显示的rank行
        let y = this.content.position.y;
        let firstRank = this.getFirstRankInView();
        let lastRank = this.getLastRankInView();

        for (let i = firstRank; i < lastRank; i++) {
            this.refreshSingle(i, this.getKeyNow());
        }
    }

    refreshSingle(rank, groupKey) {
        let curGroupKey = this.getKeyNow();
        // cc.log('refreshSingle', curGroupKey, groupKey)
        if (curGroupKey == groupKey) {
            let key = '' + rank;
            let item = this.itemMap[key];
            if (item) {
                let rowData = this.getRowDataAtRank(rank, groupKey);
                this.setItem(item, rowData, groupKey);

                let diff = this.getDiff(rank);

                // cc.log('refreshSingle', rank, this.minRefreshRank, this.maxRefreshRank, diff);
                item.appear({ type: 'refresh', diff: diff });
            }
        }
    }

    getDiff(rank) {
        let diff = 0;
        if (this.minRefreshRank >= this.maxRefreshRank) { } else {
            if (rank < this.minRefreshRank) diff = this.minRefreshRank - rank;
            if (rank > this.maxRefreshRank) diff = rank - this.maxRefreshRank;
        }
        return diff;
    }

    setItem(item, rowData, groupKey) {
        item.setItem(rowData);
        if (rowData._status == 0) {
            this.requireFetch(rowData.rank, groupKey);
        }
    }

    gotoRank(rank) {
        let y = this.itemHeight * rank + this.content.parent.getComponent(UITransform).height / 2;
        this.scrollView.content.setPosition(this.scrollView.content.getPosition().x, y, 0);
    }

    setMaxRank(rank) {
        this.maxRank = rank;
        this.content.getComponent(UITransform).height = (rank + 1) * this.itemHeight + this.tailHeight;
    }

    item_fade_in_refresh(event) {
        if (this.minRefreshRank > event.rank) this.minRefreshRank = event.rank;
        if (this.maxRefreshRank < event.rank) this.maxRefreshRank = event.rank;
        // cc.log('lb_scroll_view_refresh', event.rank, this.minRefreshRank, this.maxRefreshRank);
    }


}
